package org.shiro.demo.controller;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONObject;

import org.shiro.demo.dao.util.QueryCondition;
import org.shiro.demo.entity.GroupOrder;
import org.shiro.demo.entity.Order;
import org.shiro.demo.entity.ResponseResult;
import org.shiro.demo.entity.Ticket;
import org.shiro.demo.entity.WeixinPrepay;
import org.shiro.demo.service.IBaseService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;

import com.tenpay.Constants;
import com.tenpay.MD5;
import com.tenpay.NameValuePair;
import com.tenpay.Util;

/**
 * 微信支付服务端简单示例
 * 
 * @author seven_cm
 * @dateTime 2014-11-29
 */
@Controller
@RequestMapping("/tenpay")
public class WeixinPayController {
	@Value("#{configProperties['wcPayNotifyUrl']}")
	private String wcPayNotifyUrl;
	@Value("#{configProperties['env']}")
	private String env;
	@Resource(name = "baseService")
	private IBaseService baseService;

	public boolean jisuan(java.util.Date start, java.util.Date end) {
		long cha = end.getTime() - start.getTime();
		double result = cha * 1.0 / (1000 * 60 * 60);
		if (result <= 24) { // 24小时
			// System.out.println("可用");
			return true;
		} else {
			// System.out.println("已过期");
			return false;
		}
	}

	/**
	 * 检查订单 是否已经超时 @TODO
	 * 
	 * @param request
	 * @param response
	 * @param uuid
	 * @return
	 */
	@RequestMapping("/prepay")
	@ResponseBody
	public Object prepay(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "uuid", required = true) String uuid) {
		ResponseResult rr = new ResponseResult();
		// 判断是否超时了。支付宝只能在客户端判断是否超时。 微信支付可以再服务器段 判断是否超时
		List<QueryCondition> queryConditions = new ArrayList<QueryCondition>();
		queryConditions.add(new QueryCondition("uuid", QueryCondition.EQ, uuid));
		char c = uuid.charAt(0);
		Date postTime = null;
		double money = 0;
		switch (c) {
		case 'g':// 开团吧
			GroupOrder groupOrder = (GroupOrder) baseService.getSingleResult(GroupOrder.class, queryConditions);
			postTime = groupOrder.getPostTime();
			money = groupOrder.getMoney();
			break;
		case 't':
			Ticket ticket = (Ticket) baseService.getSingleResult(Ticket.class, queryConditions);
			postTime = ticket.getPostTime();
			money = ticket.getMoney() * 0.98;
			break;
		case 'o':
			Order order = (Order) baseService.getSingleResult(Order.class, queryConditions);
			postTime = order.getPostTime();
			money = order.getMoney();
			break;
		}
		Map<String, String> map = new HashMap<String, String>();
		if (postTime == null || !jisuan(postTime, new Date())) {
			rr.setCode(0);
			rr.setInfo("订单超时了");
			map.put("info", "error");
			rr.setObject(map);
			return rr;
		}

		String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder");
		// 查看数据库 是否有 已生成信息.. 还要判断android跟ios 的唯一性。
		WeixinPrepay prepay = baseService.getById(WeixinPrepay.class, uuid);
		try {

			if (prepay != null) {
				if (prepay.getOrderPhoneType().equals("android")) {
					JSONObject object = JSONObject.fromObject(prepay.getJson());
					// System.out.println("object" + object);
					// System.out.println("json" + prepay.getJson());
					rr.setCode(1);
					rr.setInfo("success");
					rr.setObject((Map<String, String>) object);
					return rr;
				} else {
					// 销毁ios客户端下的订单
					// baseService.delete(WeixinPrepay.class, uuid);
				}
			}
			// 生成预订单
			// System.out.println("2");
			String entity = genProductArgs(uuid, money);// 同个uuid 不能生成 相同订单号。

			System.out.println(entity);

			byte[] buf = Util.httpPost(url, entity);
			// <xml><return_code><![CDATA[SUCCESS]]></return_code>
			// <return_msg><![CDATA[OK]]></return_msg>
			// <appid><![CDATA[wxa207119c4b14badc]]></appid>
			// <mch_id><![CDATA[1235933902]]></mch_id>
			// <nonce_str><![CDATA[IvfQcFz5ZL2RGZLF]]></nonce_str>
			// <sign><![CDATA[BF0F2CC31F5ADBE4696B12F15E2455EC]]></sign>
			// <result_code><![CDATA[SUCCESS]]></result_code>
			// <prepay_id><![CDATA[wx201504061400199f9d2a10bd0546850259]]></prepay_id>
			// <trade_type><![CDATA[APP]]></trade_type>
			// </xml>
			String content = new String(buf);
			System.out.println(content);
			Map<String, String> xml = decodeXml(content);

			// 返回的map对象
			Map<String, String> return_map = genPayReqMap(xml);
			// / 生成 请求字符串
			// 这串返回的json字符串要做存储， 保证这一单prepay信息是有记录的。
			JSONObject jsonObj = JSONObject.fromObject(return_map);
			WeixinPrepay weixinPrepay = new WeixinPrepay();
			weixinPrepay.setJson(jsonObj.toString());
			weixinPrepay.setUuid(uuid);
			weixinPrepay.setOrderPhoneType("android");
			weixinPrepay.setPrepayTime(new Date());
			baseService.update(weixinPrepay);

			rr.setCode(1);
			rr.setInfo("success");
			rr.setObject(return_map);
			return rr;
		} catch (Exception e) {
			e.printStackTrace();
			return rr;
		}
	}

	@RequestMapping("/iosprepay")
	@ResponseBody
	public Object iosprepay(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "uuid", required = true) String uuid) {
		ResponseResult rr = new ResponseResult();
		// 判断是否超时了。支付宝只能在客户端判断是否超时。 微信支付可以再服务器段 判断是否超时
		List<QueryCondition> queryConditions = new ArrayList<QueryCondition>();
		queryConditions.add(new QueryCondition("uuid", QueryCondition.EQ, uuid));
		char c = uuid.charAt(0);
		Date postTime = null;
		double money = 0;
		switch (c) {
		case 'g':// 开团吧
			GroupOrder groupOrder = (GroupOrder) baseService.getSingleResult(GroupOrder.class, queryConditions);
			postTime = groupOrder.getPostTime();
			money = groupOrder.getMoney();
			break;
		case 't':
			Ticket ticket = (Ticket) baseService.getSingleResult(Ticket.class, queryConditions);
			postTime = ticket.getPostTime();
			money = ticket.getMoney()*0.98;
			break;
		case 'o':
			Order order = (Order) baseService.getSingleResult(Order.class, queryConditions);
			postTime = order.getPostTime();
			money = order.getMoney();
			break;
		}
		Map<String, String> map = new HashMap<String, String>();
		if (postTime == null || !jisuan(postTime, new Date())) {
			rr.setCode(0);
			rr.setInfo("订单超时了");
			map.put("info", "error");
			rr.setObject(map);
			return rr;
		}

		String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder");
		// 查看数据库 是否有 已生成信息..
		WeixinPrepay prepay = baseService.getById(WeixinPrepay.class, uuid);
		if (prepay != null) {
			if (prepay.getOrderPhoneType().equals("ios")) {
				JSONObject object = JSONObject.fromObject(prepay.getJson());
				rr.setCode(1);
				rr.setInfo("success");
				rr.setObject((Map<String, String>) object);
				return rr;
			} else {
				// 销毁android客户端下的订单
				// baseService.delete(WeixinPrepay.class, uuid);
			}
		}
		// 生成预订单
		String entity = genProductArgs(uuid,money);

		System.out.println(entity);

		byte[] buf = Util.httpPost(url, entity);
		// <xml><return_code><![CDATA[SUCCESS]]></return_code>
		// <return_msg><![CDATA[OK]]></return_msg>
		// <appid><![CDATA[wxa207119c4b14badc]]></appid>
		// <mch_id><![CDATA[1235933902]]></mch_id>
		// <nonce_str><![CDATA[IvfQcFz5ZL2RGZLF]]></nonce_str>
		// <sign><![CDATA[BF0F2CC31F5ADBE4696B12F15E2455EC]]></sign>
		// <result_code><![CDATA[SUCCESS]]></result_code>
		// <prepay_id><![CDATA[wx201504061400199f9d2a10bd0546850259]]></prepay_id>
		// <trade_type><![CDATA[APP]]></trade_type>
		// </xml>
		String content = new String(buf);
		System.out.println(content);
		Map<String, String> xml = decodeXml(content);
		// / 生成 请求字符串
		xml.put("package", "Sign=WXPay");

		// 返回的map对象
		Map<String, String> return_map = genIosPayReqMap(xml);
		// / 生成 请求字符串
		// 这串返回的json字符串要做存储， 保证这一单prepay信息是有记录的。
		JSONObject jsonObj = JSONObject.fromObject(return_map);
		WeixinPrepay weixinPrepay = new WeixinPrepay();
		weixinPrepay.setJson(jsonObj.toString());
		weixinPrepay.setUuid(uuid);
		weixinPrepay.setOrderPhoneType("ios");
		weixinPrepay.setPrepayTime(new Date());
		baseService.update(weixinPrepay);
		rr.setCode(1);
		rr.setInfo("success");
		rr.setObject(return_map);
		return rr;
	}

	private String genAppSign(List<NameValuePair> params) {
		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < params.size(); i++) {
			sb.append(params.get(i).getName());
			sb.append('=');
			sb.append(params.get(i).getValue());
			sb.append('&');
		}
		sb.append("key=");
		sb.append(Constants.API_KEY);

		String appSign = MD5.getMessageDigest(sb.toString().getBytes());
		System.out.println(appSign);
		return appSign;
	}

	private List<NameValuePair> genPayReq(Map<String, String> resultunifiedorder) {

		List<NameValuePair> signParams = new LinkedList<NameValuePair>();
		signParams.add(new NameValuePair("appid", Constants.APP_ID));
		signParams.add(new NameValuePair("noncestr", genNonceStr()));
		signParams.add(new NameValuePair("package", "prepay_id=" + resultunifiedorder.get("prepay_id")));
		signParams.add(new NameValuePair("partnerid", Constants.MCH_ID));
		signParams.add(new NameValuePair("prepayid", resultunifiedorder.get("prepay_id")));
		signParams.add(new NameValuePair("timestamp", String.valueOf(genTimeStamp())));
		// StringBuffer global_sb = new StringBuffer();
		String sign = genAppSign(signParams);
		signParams.add(new NameValuePair("sign", sign));
		// global_sb.append("sign\n" + sign + "\n\n");
		// 不需要返回 密钥。
		return signParams;
	}

	private Map<String, String> genPayReqMap(Map<String, String> resultunifiedorder) {
		String ss = genNonceStr();
		String tt = String.valueOf(genTimeStamp());
		Map<String, String> map = new HashMap<String, String>();
		map.put("appid", Constants.APP_ID);
		map.put("noncestr", ss);
		map.put("package", "prepay_id=" + resultunifiedorder.get("prepay_id"));
		map.put("partnerid", Constants.MCH_ID);
		map.put("prepayid", resultunifiedorder.get("prepay_id"));
		map.put("timestamp", tt);

		// 生成sign
		List<NameValuePair> signParams = new LinkedList<NameValuePair>();
		signParams.add(new NameValuePair("appid", Constants.APP_ID));
		signParams.add(new NameValuePair("noncestr", ss));
		signParams.add(new NameValuePair("package", "prepay_id=" + resultunifiedorder.get("prepay_id")));
		signParams.add(new NameValuePair("partnerid", Constants.MCH_ID));
		signParams.add(new NameValuePair("prepayid", resultunifiedorder.get("prepay_id")));
		signParams.add(new NameValuePair("timestamp", tt));
		String sign = genAppSign(signParams);

		map.put("sign", sign);
		// global_sb.append("sign\n" + sign + "\n\n");
		// 不需要返回 密钥。
		return map;
	}

	private Map<String, String> genIosPayReqMap(Map<String, String> resultunifiedorder) {
		String ss = genNonceStr();
		String tt = String.valueOf(genTimeStamp());
		Map<String, String> map = new HashMap<String, String>();
		map.put("appid", Constants.APP_ID);
		map.put("noncestr", ss);
		map.put("package", "Sign=WXPay");
		map.put("partnerid", Constants.MCH_ID);
		map.put("prepayid", resultunifiedorder.get("prepay_id"));
		map.put("timestamp", tt);

		// 生成sign
		List<NameValuePair> signParams = new LinkedList<NameValuePair>();
		signParams.add(new NameValuePair("appid", Constants.APP_ID));
		signParams.add(new NameValuePair("noncestr", ss));
		signParams.add(new NameValuePair("package", "Sign=WXPay"));
		signParams.add(new NameValuePair("partnerid", Constants.MCH_ID));
		signParams.add(new NameValuePair("prepayid", resultunifiedorder.get("prepay_id")));
		signParams.add(new NameValuePair("timestamp", tt));
		String sign = genAppSign(signParams);

		map.put("sign", sign);
		// global_sb.append("sign\n" + sign + "\n\n");
		// 不需要返回 密钥。
		return map;
	}

	public Map<String, String> decodeXml(String content) {

		try {
			Map<String, String> xml = new HashMap<String, String>();
			// 获得pull解析器工厂
			XmlPullParserFactory pullParserFactory = XmlPullParserFactory.newInstance();
			XmlPullParser parser = pullParserFactory.newPullParser();
			parser.setInput(new StringReader(content));
			int event = parser.getEventType();
			while (event != XmlPullParser.END_DOCUMENT) {

				String nodeName = parser.getName();
				switch (event) {
				case XmlPullParser.START_DOCUMENT:

					break;
				case XmlPullParser.START_TAG:

					if ("xml".equals(nodeName) == false) {
						// 实例化student对象
						xml.put(nodeName, parser.nextText());
					}
					break;
				case XmlPullParser.END_TAG:
					break;
				}
				event = parser.next();
			}

			return xml;
		} catch (Exception e) {
			System.out.println(e.toString());
		}
		return null;

	}

	private String genProductArgs(String uuid, double money) {
		// money 是元，要转成分。
		String finalmoney = String.format("%.2f", money);
		finalmoney = finalmoney.replace(".", "");// 变成分
		finalmoney =  String.valueOf(Integer.parseInt(finalmoney));//去掉前面的0
		StringBuffer xml = new StringBuffer();

		try {
			String nonceStr = genNonceStr();

			xml.append("</xml>");
			List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
			packageParams.add(new NameValuePair("appid", Constants.APP_ID));
			packageParams.add(new NameValuePair("body", "dxyxx APP pay"));// 需要
																			// 传递商品名字
			packageParams.add(new NameValuePair("mch_id", Constants.MCH_ID));
			packageParams.add(new NameValuePair("nonce_str", nonceStr));
			// packageParams.add(new
			// NameValuePair("notify_url","http://pay.dxyxx.com:8081/pay/tenpay/deal.xml"));
			packageParams.add(new NameValuePair("notify_url", wcPayNotifyUrl));
			packageParams.add(new NameValuePair("out_trade_no", uuid)); // 需要传递
																		// 的order
																		// id
			packageParams.add(new NameValuePair("spbill_create_ip", "127.0.0.1"));
			packageParams.add(new NameValuePair("total_fee", finalmoney));// 金额
			packageParams.add(new NameValuePair("trade_type", "APP"));

			String sign = genPackageSign(packageParams);
			packageParams.add(new NameValuePair("sign", sign));

			String xmlstring = toXml(packageParams);

			return xmlstring;

		} catch (Exception e) {
			System.out.println("genProductArgs fail, ex = " + e.getMessage());
			return null;
		}

	}

	/**
	 * 生成签名
	 */

	private String genPackageSign(List<NameValuePair> params) {
		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < params.size(); i++) {
			sb.append(params.get(i).getName());
			sb.append('=');
			sb.append(params.get(i).getValue());
			sb.append('&');
		}
		sb.append("key=");
		sb.append(Constants.API_KEY);

		String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
		System.out.println(packageSign);
		return packageSign;
	}

	private String toXml(List<NameValuePair> params) {
		StringBuilder sb = new StringBuilder();
		sb.append("<xml>");
		for (int i = 0; i < params.size(); i++) {
			sb.append("<" + params.get(i).getName() + ">");

			sb.append(params.get(i).getValue());
			sb.append("</" + params.get(i).getName() + ">");
		}
		sb.append("</xml>");

		System.out.println(sb.toString());
		return sb.toString();
	}

	private String genNonceStr() {
		Random random = new Random();
		return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
	}

	private long genTimeStamp() {
		return System.currentTimeMillis() / 1000;
	}

	private String genOutTradNo() {
		Random random = new Random();
		return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
	}

}